//------------------------------------------------------------------------
// Abstract: Implement of relative Structure of database
//
// Authoring: XiaoHanxiong
//
// Time: 2014.04.20
//
// Static test:
//
// Version history:
//		Ver_1.0	: 2014.04.20	XiaoHanxiong
//------------------------------------------------------------------------
#include "DBStructure.h"

namespace Database
{
	Field::Field( const char* field_name, FieldType type, FieldConstraint flag /*= EFT_None*/ )
		: m_name(field_name)
		, m_type(type)
		, m_constraint(flag)
		, m_index(-1)
	{

	}

	Field::Field()
		: m_type(EFT_NULL)
		, m_constraint(EFC_None)
		, m_name()
		, m_index(-1)
	{

	}

	Field::Field( const Field& field )
		: m_name(field.m_name)
		, m_type(field.m_type)
		, m_constraint(field.m_constraint)
		, m_index(field.m_index)
	{

	}

	Field::~Field()
	{

	}

	string Field::GetFieldName()
	{
		return m_name;
	}

	int Field::GetFieldIndex()
	{
		return m_index;
	}

	FieldType Field::GetFieldType()
	{
		return m_type;
	}

	FieldConstraint Field::GetFieldConstraint()
	{
		return m_constraint;
	}

	void Field::Clear()
	{
		m_name.clear();
		m_type = EFT_NULL;
		m_index = (-1);
		m_constraint = EFC_None;
	}

	void Field::Copy(const Field& field)
	{
		m_name = field.m_name;
		m_type = field.m_type;
		m_constraint = field.m_constraint;
		m_index = field.m_index;
	}


	//////////////////////////////////////////////////////////////////////////
	DataContainer::DataContainer()
	{
		m_data_flag = _Null;
		m_data.um_uint64 = 0;
	}

	DataContainer::DataContainer( const DataContainer& data )
	{
		Copy(data);
	}

	DataContainer::~DataContainer()
	{
		Clear();
	}

	DataContainer::DataFlag DataContainer::GetDataFlag()
	{
		return m_data_flag;
	}

	bool DataContainer::IsNull()
	{
		return (m_data_flag == _Null);
	}

	int DataContainer::GetDataSize()
	{
		switch(m_data_flag)
		{
		case _Int64:
			return sizeof(__int64);

		case _Double:
			return sizeof(double);

		case _Blob:
		case _String:
			return m_data.um_blob.m_size;

		default:
			return 0;
		}
	}

	void DataContainer::Clear()
	{
		// If it is the blob, free the keep memory
		if(m_data_flag == _Blob || m_data_flag == _String)
		{
			if(m_data.um_blob.m_ptr != NULL)
			{
				delete [] m_data.um_blob.m_ptr;
				m_data.um_blob.m_ptr = NULL;
			}
		}

		// Set 0 to the whole union value
		m_data.um_uint64 = 0;
		m_data_flag = _Null;
	}

	void DataContainer::Copy( const DataContainer& data )
	{
		switch(data.m_data_flag)
		{
		case _Int64:
			SetData(data.m_data.um_uint64);
			break;

		case _Double:
			SetData(data.m_data.um_double);			
			break;

		case _Blob:
			SetData(data.m_data.um_blob.m_ptr, data.m_data.um_blob.m_size);
			break;

		case _String:
			SetData(data.m_data.um_blob.m_ptr, data.m_data.um_blob.m_size);
			m_data_flag = _String;
			break;

		default:
			Clear();
			break;
		}
	}

	bool DataContainer::SetData( unsigned __int64 value )
	{
		Clear();
		m_data.um_uint64 = value;
		m_data_flag = _Int64;
		return true;
	}

	bool DataContainer::SetData( double value )
	{
		Clear();
		m_data.um_double = value;
		m_data_flag = _Double;
		return true;
	}

	bool DataContainer::SetData( const string& str )
	{
		Clear();
		if(str.size() > 0)
		{
			m_data.um_blob.m_ptr = new BYTE[str.size() + 1]();
			memcpy(m_data.um_blob.m_ptr, str.data(), str.size() + 1);
			m_data.um_blob.m_size = str.size();
		}
		m_data_flag = _String;
		return true;
	}

	bool DataContainer::SetData( const void* pointer, int data_size )
	{
		Clear();
		if(data_size > 0)
		{
			m_data.um_blob.m_ptr = new BYTE[data_size]();
			memcpy(m_data.um_blob.m_ptr, pointer, data_size);
			m_data.um_blob.m_size = data_size;
		}
		m_data_flag = _Blob;
		return true;
	}

	bool DataContainer::GetData( unsigned __int64& value )
	{
		if(m_data_flag == _Int64)
		{
			value = m_data.um_uint64;
			return true;
		}
		else return false;
	}

	bool DataContainer::GetData( double& value )
	{
		if(m_data_flag == _Double)
		{
			value = m_data.um_double;
			return true;
		}
		else return false;
	}

	bool DataContainer::GetData( string& str )
	{
		if(m_data_flag == _String)
		{
			str = static_cast<char*>(m_data.um_blob.m_ptr);
			return true;
		}
		return false;
	}

	bool DataContainer::GetData( void*& pointer, int buffer_size )
	{
		if((m_data_flag == _Blob || m_data_flag == _String) &&
			m_data.um_blob.m_size < buffer_size && m_data.um_blob.m_size != 0)
		{
			memcpy(pointer, m_data.um_blob.m_ptr, m_data.um_blob.m_size);
			return true;
		}
		else return false;
	}


	//////////////////////////////////////////////////////////////////////////
	Record::Record()
	{

	}

	Record::Record( const Record& record )
		: m_record(record.m_record)
	{

	}

	Record::~Record()
	{

	}

	DataContainer& Record::GetDataContainer( int index )
	{
		if(m_record.find(index) == m_record.end())
		{
			m_record.insert(std::make_pair(index, DataContainer()));
		}

		return m_record[index];
	}

	bool Record::AddColumnData( const DataContainer& column_data, int index )
	{
		if(m_record.find(index) == m_record.end())
		{
			m_record[index] = column_data;
			return true;
		}
		return false;
	}

	bool Record::AssignColumnData( const DataContainer& column_data, int index )
	{
		DataContainerMap::iterator itr = m_record.begin();
		if(itr != m_record.end())
		{
			itr->second.Copy(column_data);
			return true;
		}
		return false;
	}

	bool Record::DeleteColumnData( int index )
	{
		DataContainerMap::iterator itr = m_record.begin();
		if(itr != m_record.end())
		{
			m_record.erase(itr);
			return true;
		}
		return false;
	}

	void Record::ClearRecord()
	{
		m_record.clear();
	}

	void Record::SwapData( Record& record )
	{
		m_record.swap(record.m_record);
	}


	//////////////////////////////////////////////////////////////////////////
	Table::Table( const Table& table )
		: m_table_name(table.m_table_name)
		, m_field_map(table.m_field_map)
	{

	}

	Table::Table()
	{

	}

	Table::~Table()
	{

	}

	bool Table::AddField( Field& field )
	{
		Field& new_field = field;
		int count = m_field_map.size();

		if(m_field_map.find(new_field.m_name) == m_field_map.end())
		{
			new_field.m_index = count;
			m_field_map[new_field.m_name] = new_field;
			return true;
		}
		else return false;
	}
	
	bool Table::AddField(string field_name, FieldType type, FieldConstraint flag /* = EFT_None */)
	{
		Field field(field_name.c_str(), type, flag);
		return AddField(field);
	}

	bool Table::GetField( string field_name, Field& field )
	{
		FieldMap::iterator itr = m_field_map.find(field_name);
		if(itr != m_field_map.end())
		{
			field = itr->second;
			return true;
		}
		else return false;
	}

	bool Table::GetField( int index, Field& field )
	{
		FieldMap::iterator itr = m_field_map.begin();
		for( ; itr != m_field_map.end(); itr++ )
		{
			if(itr->second.m_index == index)
			{
				field = itr->second;
				return true;
			}
		}

		return false;
	}

	bool Table::RemoveField( string field_name )
	{
		FieldMap::iterator itr = m_field_map.find(field_name);
		if(itr != m_field_map.end())
		{
			m_field_map.erase(itr);
			return true;
		}
		else return false;
	}

	bool Table::RemoveField( int index )
	{
		FieldMap::iterator itr = m_field_map.begin();
		for( ; itr != m_field_map.end(); itr++ )
		{
			if(itr->second.m_index == index)
			{
				m_field_map.erase(itr);
				return true;
			}
		}

		return false;
	}

	int Table::GetFieldCount()
	{
		return static_cast<int>(m_field_map.size());
	}

	void Table::CopyTableInfo( Table& table )
	{
		m_field_map = table.m_field_map;
		m_table_name = table.m_table_name;
	}

	Table::FieldMap& Table::GetFieldMap()
	{
		return m_field_map;
	}

	string Table::GetTableName()
	{
		return m_table_name;
	}

	void Table::SetTableName( string table_name )
	{
		m_table_name = table_name;
	}

	Record& Table::AppendNewRecord()
	{
		m_record_clt.push_back(Record());
		return m_record_clt.back();
	}

	void Table::AppendRecord( Record& record )
	{
		m_record_clt.push_back(record);
	}

	void Table::ClearRecord()
	{
		m_record_clt.clear();
	}

	Table::RecordColloction& Table::GetRecordColloction()
	{
		return m_record_clt;
	}

}// _Database